home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
applic
/
ntp
/
minimuf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-29
|
15KB
|
437 lines
/*
***********************************************************************
* Program to calculate maximum usable frequency and received signal *
* strength for high-frequency radio circuits. Uses MINIMUF 3.5. *
***********************************************************************
input format:
first line contains five numbers:
3 1 1 194 20
1. output format
1 receiver power (dB/uV)
2 elevation angle (deg)
3 delay (ms)
2. month (1-12)
3. day (1-31)
4. smoothed sunspot number
5. transmitter ERP (dBW)
second line contains transmitter coordinates and name:
39.7000 -75.7825 W3HCF Newark
third and subsequent lines contain receiver coordinates
and name:
39.6808 -75.7486 Evans Hall
45.18 -75.45 CHU Ottawa
40.6803 -105.0408 WWV Ft Collins
21.9906 -159.7667 WWVH Hawaii
52.3667 -1.1833 MSF Rugby
timecode transmitters, frequencies and geographic coordinates
WWV Ft. Collins, CO 2.5, 5, 10, 15, 20 MHz 40:40N, 105:03W
WWVB Ft. Collins, CO 60 kHz 40:40:49N, 105:02:27W
WWVH Kauai, HI 2.5, 5, 10, 15, 20 MHz 21:59:26N, 159:46:00W
CHU Ottawa, Canada 3330, 7335, 14670 45:18N, 75:45N
MSF Rugby, UK 60 kHz, 2.5, 5, 10 MHz 52:22N, 1:11W
*/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
/*
Parameters
*/
#define R 6371.2 /* radius of the Earth (km) */
#define hE 110. /* height of E layer (km) */
#define hF 320. /* height of F layer (km) */
#define GAMMA 1.42 /* geomagnetic constant */
#define PI 3.141592653589 /* the real thing */
#define PIH PI/2. /* the real thing/2 */
#define PID 2.*PI /* the real thing*2 */
#define VOFL 2.9979250e8 /* velocity of light */
#define D2R PI/180. /* degrees to radians */
#define R2D 180./PI /* radians to degrees */
#define MINBETA 5.*D2R /* min elevation angle (rad) */
#define RINZ 50. /* receiver input impedance (ohms) */
#define BOLTZ 1.380622e-23 /* Boltzmann's constant */
#define NTEMP 273. /* receiver noise temperature (deg K) */
#define DELTAF 2400. /* communication bandwidth (Hz) */
#define MPATH 3. /* multipath threshold (dB) */
#define GLOSS 3. /* ground-reflection loss (dB) */
#define FMAX 8 /* max frequencies */
#define HMAX 10 /* max hops */
/*
Function declarations
*/
extern FILE *fopen();
static double minimuf(void), sgn(double); void edit(int);
/*
Global declarations
*/
int month; /* month of year (1-12) */
int day; /* day of month*/
int hour; /* hour of day (UTC) */
double freq[FMAX]; /* frequencies (MHz) */
double gain[46][FMAX]; /* antenna gain (main lobe) (dB) */
double dB1; /* transmitter output power (dBW) */
double ssn; /* smoothed sunspot number */
double lat1; /* transmitter latitude (deg N) */
double lon1; /* transmitter longitude (deg W) */
char site1[30]; /* transmitter site name */
double lat2; /* receiver latitude (deg N) */
double lon2; /* receiver longitude (deg W) */
char site2[30]; /* receiver site name */
double b1; /* transmitter bearing (rad) */
double b2; /* receiver bearing (rad) */
double d; /* great-circle distance (rad) */
double theta; /* hour angle (rad) */
int hop; /* number of ray hops */
double phi; /* angle of incidence (rad) */
FILE *fp_in; /* file handle */
char fn_in[12] = "gain.dat"; /* antenna file name */
char fq_in[12] = "ntp.dat"; /* qth file name */
int flag; /* output format */
/*
Main program
*/
main() {
/*
Hour variables
*/
int offset; /* offset for local time (hours) */
int time; /* local time at receiver */
char daynight[HMAX]; /* day/night indicator (jnx) */
double mufE[HMAX]; /* max E-layer muf (MHz) */
double mufF[HMAX]; /* min F-layer muf (MHz) */
double absorp[HMAX]; /* ionospheric absorption coefficient */
double dB2[HMAX]; /* receiver input power (dBuV) */
double path[HMAX]; /* path length (km) */
double beta[HMAX]; /* elevation angle (rad) */
double ant[HMAX]; /* antenna gain (dB) */
/*
Path variables
*/
double delay; /* path distance (ms) */
double dhop; /* hop angle/2 (rad) */
int daytime, nightime; /* path indicators */
double psi; /* sun zenith angle (rad) */
double xr, yr; /* reflection zone coordinates (rad) */
double xs, ys, yp; /* subsolar coordinates (rad) */
double fcE; /* E-layer critical frequency (MHz) */
double fcF; /* F-layer critical frequency (MHz) */
char cutoff; /* layer cutoff indicator (EFM) */
double beta1, phi1, level, muf, dist, Z, floor; /* double temporaries */
int i,j,h,n; /* int temporaries */
float fp1, fp2; /* float temporaries */
/*
Establish initial conditions
*/
if ((fp_in = fopen (fn_in, "r")) == NULL) {
printf ("Antenna file %s not found\n", fn_in); exit (1);
}
for (j = 0; j < FMAX; j++) {
fscanf(fp_in, " %f ", &fp1);
freq[j] = fp1;
}
for (i = 0; i < 46; i++) {
for (j = 0; j < FMAX; j++) {
fscanf(fp_in, " %f ", &fp1);
gain[i][j] = fp1;
}
}
if ((fp_in = fopen (fq_in, "r")) == NULL) {
printf ("QTH file %s not found\n", fq_in); exit (2);
}
if (fscanf(fp_in, " %i %i %i %f %f", &flag, &month, &day, &fp1, &fp2)
!= 5) exit (0);
ssn = fp1; dB1 = fp2;
if (fscanf(fp_in, " %f %f %[^\n]", &fp1, &fp2, site1) != 3) exit (0);
lat1 = fp1*D2R; lon1 = -fp2*D2R;
printf("Transmitter %s\n", site1);
L1: if (fscanf(fp_in, " %f %f %[^\n]", &fp1, &fp2, site2) != 3) exit (0);
lat2 = fp1*D2R; lon2 = -fp2*D2R;
printf("Receiver %s\n", site2);
/*
Compute great-circle bearings, great-circle distance, min hops and path delay
*/
theta = lon1-lon2;
if (theta >= PI) theta = theta-PID;
if (theta <= -PI) theta = theta+PID;
d = acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(theta));
if (d < 0.) d = PI+d;
b1 = acos((sin(lat2)-sin(lat1)*cos(d))/(cos(lat1)*sin(d)));
if (b1 < 0.) b1 = PI+b1;
if (theta < 0) b1 = PID-b1;
b2 = acos((sin(lat1)-sin(lat2)*cos(d))/(cos(lat2)*sin(d)));
if (b2 < 0.) b2 = PI+b2;
if (theta >= 0.) b2 = PID-b2;
hop = d/(2.*acos(R/(R+hF)));
beta1 = 0.;
while (beta1 < MINBETA) {
hop = hop+1;
dhop = d/(hop*2.);
beta1 = atan((cos(dhop)-R/(R+hF))/sin(dhop));
}
phi = R*cos(beta1)/(R+hE);
phi = atan(phi/sqrt(1.-phi*phi));
delay = 2.*hop*sin(dhop)*(R+hF)/cos(beta1)/VOFL*1e6;
printf("\nSmoothed sunspot number:%4.0f Month:%3i Day:%3i\n",
ssn, month, day);
printf("Power:%3.0f dBW Distance:%6.0f km Delay:%5.1f ms\n",
dB1, d*R, delay);
printf("Location Lat Long Azim\n");
printf("%-27s %7.2fN %7.2fW %3.0f\n", site1, lat1*R2D, lon1*R2D, b1*R2D);
printf("%-27s %7.2fN %7.2fW %3.0f\n", site2, lat2*R2D, lon2*R2D, b2*R2D);
printf("UT LT MUF%8.1f%8.1f%8.1f%8.1f%8.1f%8.1f%8.1f%8.1f\n"
, freq[0], freq[1], freq[2], freq[3], freq[4], freq[5],
freq[6], freq[7]);
/*
Hour loop: This loop determines the min-hop path and next two higher-hop
paths. It selects the most likely path for each frequency and calculates the
receiver power. The minimum F-layer MUF is computed directly from MINIMUF 3.5
and regardless of the actual number of hops, geographic coordinates or time
of day.
*/
offset = lon2*12./PI+.5;
for (hour = 0; hour < 24; hour++) {
time = hour-offset;
if (time < 0) time = time+24;
if (time >= 24) time = time-24;
muf = minimuf();
fcF = muf * cos(phi);
printf("%2i %2i", hour, time);
/* subsolar coordinates */
xs = (month-1.)*365.25/12.+day-80.;
xs = 23.5*D2R*sin(xs/365.25*PID);
ys = (hour*15.-180.)*D2R;
/*
Path loop: This loop determines the geometry of the min-hop path and the next
two hiher-hop paths. It calculates the minimum F-layer MUF, maximum E-layer
MUF and ionospheric absorption factor for each path.
*/
for (h = hop; h < hop+2; h++) {
daytime = 0.;
nightime = 0.;
mufE[h] = 0.;
absorp[h] = 0.;
daynight[h] = ' ';
/* path geometry, min F-layer MUF */
dhop = d/(h*2.);
beta1 = atan((cos(dhop)-R/(R+hF))/sin(dhop));
phi1 = R*cos(beta1)/(R+hE);
phi1 = atan(phi1/sqrt(1.-phi1*phi1));
mufF[h] = fcF/cos(phi1);
/*
Hop loop: This loop calculates the reflection zones and subsolar zenith angle
for each hop along the path. It then computes the minimum E-layer MUF and
ionospheric absorption coeeficient for the total path.
*/
for (dist = dhop; dist < d; dist = dist+dhop*2) {
/* reflection zone coordinates */
xr = acos(cos(dist)*sin(lat1)+sin(dist)*cos(lat1)*cos(b1));
if (xr < 0.) xr = PI+xr;
xr = PIH-xr;
yr = acos((cos(dist)-sin(xr)*sin(lat1))/(cos(xr)*cos(lat1)));
if (yr < 0.) yr = PI+yr;
if (theta < 0.) yr = -yr;
yr = lon1-yr;
if (yr >= PI) yr = yr-PID;
if (yr <= -PI) yr = yr+PID;
yp = ys-yr;
if (yp > PI) yp = PID-yp;
if (yp < -PI) yp = -PID+yp;
/* E-layer MUF */
psi = acos(sin(xr)*sin(xs)+cos(xr)*cos(xs)*cos(yp));
if (psi < 0.) psi = PI+psi;
Z = cos(psi);
if (Z > 0.) {
Z = .9*pow((180.+1.44*ssn)*Z,.25);
if (Z < .005*ssn) Z = .005*ssn;
}
else Z = .005*ssn;
Z = Z/cos(phi1);
if (Z > mufE[h]) mufE[h] = Z;
/* ionospheric absorption coeeficient */
Z = psi;
if (Z > 100.8*D2R) {
Z = 100.8*D2R;
nightime++;
}
else daytime++;
Z = cos(90./100.8*Z);
if (Z < 0.) Z = 0;
Z = (1.+.0037*ssn)*pow(Z,1.3);
if (Z < .1) Z = .1;
absorp[h] = absorp[h]+Z;
}
/* path flags */
if (daytime > 0.) daynight[h] = 'j';
if (nightime > 0.) daynight[h] = 'n';
if ((daytime > 0.) && (nightime > 0.)) daynight[h] = 'x';
}
/*
Frequency loop: This loop calculates the receiver power for each frequency
and path. It discards paths above the minimum F-layer MUF or below the
maximum E-layer MUF and selects the path with maximum power. It then
calculates the combined power of the remaining paths and determines if
multipath conditions exist.
*/
printf("%5.1f ", mufF[hop]);
for (i = 0; i < FMAX; i++) {
level = -1e6; j = 0;
/* receiver power for each path */
for (h = hop; h < hop+2; h++) {
dhop = d/(h*2.);
switch (daynight[h]) {
case 'n': Z = 250.; break;
case 'j': Z = 350.; break;
default: Z = hF;
}
beta[h] = atan((cos(dhop)-R/(R+Z))/sin(dhop));
phi1 = R*cos(beta[h])/(R+hE);
phi1 = atan(phi1/sqrt(1.-phi1*phi1));
path[h] = 2.*h*sin(dhop)*(R+Z)/cos(beta[h]);
dB2[h] = -1e6;
if ((freq[i] < mufF[h]) && (freq[i] > mufE[h])) {
Z = dB1+137.;
Z = Z-32.44-20.*log10(path[h])-h*GLOSS;
Z = Z-8.686*log(freq[i]);
Z = Z-677.2*absorp[h]/cos(phi1)
/(pow((freq[i]+GAMMA),
1.98)+10.2);
muf = modf(beta[h]*R2D/2., &dist);
n = dist;
ant[h] = gain[n][i]+muf*(gain[n+1][i]-gain[n][i]);
Z = Z+ant[h]; dB2[h] = Z;
if (dB2[h] > level) {
level = dB2[h]; j = h;;
}
}
}
/* select path and determine multipath */
floor = 20.*log10(sqrt(4.*RINZ*BOLTZ*NTEMP*DELTAF))+120.;
muf = 0.;
if (j > 0) {
for (h = hop; h < hop+2; h++)
muf = muf+exp(dB2[h]/10.);
muf = 10.*log10(muf); cutoff = ' ';
if (dB2[j] < muf+MPATH) cutoff = 'm';
if (dB2[j] < floor) cutoff = 's';
switch (flag) {
case 1: printf("%5.0f%c%1i%c",
dB2[j],
daynight[j], j, cutoff);
break;
case 2: printf("%5.1f%c%1i%c",
beta[j]*R2D,
daynight[j], j, cutoff);
break;
case 3: printf("%5.1f%c%1i%c",
path[j]/300,
daynight[j], j, cutoff);
}
}
else {
printf(" ");
}
}
printf("\n");
}
goto L1;
}
/*
MINIMUF 3.5 (From QST December 1982)
Inputs
lat1 = transmitter latitude, lon1 = transmitter longitude
lat2 = receiver latitude, lon2 = receiver longitude
month = month of year
day = day of month
hour = UTC hour, ssn = sunspot number
Outputs
mufF = F-layer MUF
*/
double minimuf() {
double MUF;
double A, B, C, D, P, Q;
double Y1, Y2;
double T, T4, T6, T9;
double G0, G1, G2, G7, G8, G9;
double K, K1, K5, K6, K7, K8, K9;
double M9, C0, U, U1, W0, L0;
K7 = sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon2-lon1);
if (K7 < -1.) K7 = -1.; if (K7 > 1.) K7 = 1.; G1 = acos(K7);
K6 = 1.59*G1; if (K6 < 1.) K6 = 1.; K5 = 1./K6; MUF = 100.;
for (K1 = 1./(2.*K6); K1 <= 1.-1./(2.*K6); K1 = K1+fabs(.9999-1./K6)) {
if (K5 != 1.) K5 = .5;
P = sin(lat2); Q = cos(lat2);
A = (sin(lat1)-P*cos(G1))/(Q*sin(G1));
B = G1*K1; C = P*cos(B)+Q*sin(B)*A;
D = (cos(B)-C*P)/(Q*sqrt(1.-C*C));
if (D < -1.) D = -1.; if (D > 1.) D = 1.; D = acos(D);
W0 = lon2+sgn(sin(lon1-lon2))*D;
if (W0 < 0) W0 = W0+PID; if (W0 >= PID) W0 = W0-PID;
if (C < -1.) C = -1.; if (C > 1.) C = 1.; L0 = PIH-acos(C);
Y1 = .0172*(10.+(month-1.)*30.4+day);
Y2 = .409*cos(Y1);
K8 = 3.82*W0+12.+.13*(sin(Y1)+1.2*sin(2.*Y1));
K8 = K8-12.*(1.+sgn(K8-24.))*sgn(fabs(K8-24.));
if (cos(L0+Y2) > -.26) goto s1520;
K9 = 0.; G0 = 0.; M9 = 2.5*G1*K5; if (M9 > PIH) M9 = PIH;
M9 = sin(M9); M9 = 1.+2.5*M9*sqrt(M9);
goto s1770;
s1520: K9 = (-.26+sin(Y2)*sin(L0))/(cos(Y2)*cos(L0)+.001);
K9 = 12.-atan(K9/sqrt(fabs(1.-K9*K9)))*7.639437;
T = K8-K9/2.+12.*(1.-sgn(K8-K9/2.))*sgn(fabs(K8-K9/2.));
T4 = K8+K9/2.-12.*(1.+sgn(K8+K9/2.-24.))*sgn(fabs(K8+K9/2-24.));
C0 = fabs(cos(L0+Y2));
T9 = 9.7*pow(C0,9.6); if (T9 < .1) T9 = .1;
M9 = 2.5*G1*K5; if (M9 > PIH) M9 = PIH;
M9 = sin(M9); M9 = 1.+2.5*M9*sqrt(M9);
if (T4 < T) goto s1680;
if ((hour-T)*(T4-hour) > 0.) goto s1690;
goto s1820;
s1680: if ((hour-T4)*(T-hour) > 0.) goto s1820;
s1690: T6 = hour+12.*(1.+sgn(T-hour))*sgn(fabs(T-hour));
G9 = PI*(T6-T)/K9; G8 = PI*T9/K9; U = (T-T6)/T9;
G0 = C0*(sin(G9)+G8*(exp(U)-cos(G9)))/(1.+G8*G8);
G7 = C0*(G8*(exp(-K9/T9)+1.))*exp((K9-24)/2.)/(1.+G8*G8);
if (G0 < G7) G0 = G7;
goto s1770;
s1770: G2 = (1.+ssn/250.)*M9*sqrt(6.+58.*sqrt(G0));
G2 = G2*(1.-.1*exp((K9-24.)/3.));
G2 = G2*(1.+(1.-sgn(lat1)*sgn(lat2))*.1);
G2 = G2*(1.-.1*(1.+sgn(fabs(sin(L0))-cos(L0))));
goto s1880;
s1820: T6 = hour+12.*(1.+sgn(T4-hour))*sgn(fabs(T4-hour));
G8 = PI*T9/K9; U = (T4-T6)/2.; U1 = -K9/T9;
G0 = C0*(G8*(exp(U1)+1.))*exp(U)/(1.+G8*G8);
goto s1770;
s1880: if (MUF > G2) MUF = G2;
}
return (MUF);
}
/*
sgn function (like BASIC)
*/
double sgn(double x) {
if (x > 0.) return (1.);
if (x < 0.) return (-1.);
return (0);
}